@@ -77,6 +77,7 @@ urlpatterns += [  | 
            ||
| 77 | 77 | 
                # 支付相关  | 
            
| 78 | 78 | 
                urlpatterns += [  | 
            
| 79 | 79 | 
                url(r'^wx/order_create$', pay_views.wx_order_create_api, name='wx_order_create_api'), # 订单创建  | 
            
| 80 | 
                + url(r'^wx/order_query$', pay_views.wx_order_query_api, name='wx_order_query_api'), # 订单查询  | 
            |
| 80 | 81 | 
                url(r'^wx/notify_url$', pay_views.wx_notify_url_api, name='wx_notify_url_api'), # 支付异步通知回调地址  | 
            
| 81 | 82 | 
                ]  | 
            
| 82 | 83 | 
                 | 
            
                @@ -0,0 +1,19 @@  | 
            ||
| 1 | 
                +# -*- coding: utf-8 -*-  | 
            |
| 2 | 
                +from __future__ import unicode_literals  | 
            |
| 3 | 
                +  | 
            |
| 4 | 
                +from django.db import models, migrations  | 
            |
| 5 | 
                +  | 
            |
| 6 | 
                +  | 
            |
| 7 | 
                +class Migration(migrations.Migration):  | 
            |
| 8 | 
                +  | 
            |
| 9 | 
                + dependencies = [  | 
            |
| 10 | 
                +        ('pay', '0001_initial'),
               | 
            |
| 11 | 
                + ]  | 
            |
| 12 | 
                +  | 
            |
| 13 | 
                + operations = [  | 
            |
| 14 | 
                + migrations.AddField(  | 
            |
| 15 | 
                + model_name='orderinfo',  | 
            |
| 16 | 
                + name='trade_type',  | 
            |
| 17 | 
                + field=models.CharField(help_text='\u652f\u4ed8\u65b9\u5f0f', max_length=255, null=True, verbose_name='trade_type', blank=True),  | 
            |
| 18 | 
                + ),  | 
            |
| 19 | 
                + ]  | 
            
                @@ -10,13 +10,26 @@ from pai2.basemodels import CreateUpdateMixin  | 
            ||
| 10 | 10 | 
                 | 
            
| 11 | 11 | 
                 | 
            
| 12 | 12 | 
                class OrderInfo(CreateUpdateMixin):  | 
            
| 13 | 
                + """  | 
            |
| 14 | 
                + # Trade State of Wechat Query  | 
            |
| 15 | 
                + SUCCESS ——— 支付成功  | 
            |
| 16 | 
                + REFUND ——— 转入退款  | 
            |
| 17 | 
                + NOTPAY ——— 未支付  | 
            |
| 18 | 
                + CLOSED ——— 已关闭  | 
            |
| 19 | 
                + REVOKED ——— 已撤销(刷卡支付)  | 
            |
| 20 | 
                + USERPAYING ——— 用户支付中  | 
            |
| 21 | 
                + PAYERROR ——— 支付失败(其他原因,如银行返回失败)  | 
            |
| 22 | 
                + """  | 
            |
| 23 | 
                +  | 
            |
| 13 | 24 | 
                WAITING_PAY = 0  | 
            
| 14 | 25 | 
                PAID = 1  | 
            
| 15 | 
                - # DELETED = 2  | 
            |
| 26 | 
                + FAIL = 2  | 
            |
| 27 | 
                + # DELETED = 9  | 
            |
| 16 | 28 | 
                 | 
            
| 17 | 29 | 
                PAY_STATUS = (  | 
            
| 18 | 30 | 
                (WAITING_PAY, u'待支付'),  | 
            
| 19 | 31 | 
                (PAID, u'已支付'),  | 
            
| 32 | 
                + (FAIL, u'已失败'),  | 
            |
| 20 | 33 | 
                # (DELETED, u'已删除'),  | 
            
| 21 | 34 | 
                )  | 
            
| 22 | 35 | 
                 | 
            
                @@ -29,6 +42,8 @@ class OrderInfo(CreateUpdateMixin):  | 
            ||
| 29 | 42 | 
                body = models.CharField(_(u'body'), max_length=255, blank=True, null=True, help_text=u'商品描述')  | 
            
| 30 | 43 | 
                total_fee = models.IntegerField(_(u'total_fee'), default=0, help_text=u'总金额')  | 
            
| 31 | 44 | 
                 | 
            
| 45 | 
                +    trade_type = models.CharField(_('trade_type'), max_length=255, blank=True, null=True, help_text=u'支付方式')
               | 
            |
| 46 | 
                +  | 
            |
| 32 | 47 | 
                pay_status = models.IntegerField(_(u'pay_status'), choices=PAY_STATUS, default=WAITING_PAY, help_text=u'支付状态', db_index=True)  | 
            
| 33 | 48 | 
                paid_at = models.DateTimeField(_(u'paid_at'), blank=True, null=True, help_text=_(u'支付时间'))  | 
            
| 34 | 49 | 
                 | 
            
                @@ -45,7 +45,13 @@ def wx_order_create_api(request):  | 
            ||
| 45 | 45 | 
                     wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
               | 
            
| 46 | 46 | 
                 | 
            
| 47 | 47 | 
                # 生成订单  | 
            
| 48 | 
                - order = OrderInfo.objects.create(from_uid=from_uid, to_lid=to_lid, to_uid=to_uid, total_fee=total_fee)  | 
            |
| 48 | 
                + order = OrderInfo.objects.create(  | 
            |
| 49 | 
                + from_uid=from_uid,  | 
            |
| 50 | 
                + to_lid=to_lid,  | 
            |
| 51 | 
                + to_uid=to_uid,  | 
            |
| 52 | 
                + total_fee=total_fee,  | 
            |
| 53 | 
                + trade_type=trade_type,  | 
            |
| 54 | 
                + )  | 
            |
| 49 | 55 | 
                 | 
            
| 50 | 56 | 
                try:  | 
            
| 51 | 57 | 
                prepay_data = wxpay.order.create(  | 
            
                @@ -67,6 +73,8 @@ def wx_order_create_api(request):  | 
            ||
| 67 | 73 | 
                 | 
            
| 68 | 74 | 
                     return JsonResponse({
               | 
            
| 69 | 75 | 
                'status': 200,  | 
            
| 76 | 
                + 'message': 'Order Create Success',  | 
            |
| 77 | 
                + 'description': u'订单创建成功',  | 
            |
| 70 | 78 | 
                         'data': {
               | 
            
| 71 | 79 | 
                'order_id': order.order_id,  | 
            
| 72 | 80 | 
                'prepay_id': prepay_id,  | 
            
                @@ -84,6 +92,75 @@ def order_paid_success(order):  | 
            ||
| 84 | 92 | 
                order.save()  | 
            
| 85 | 93 | 
                 | 
            
| 86 | 94 | 
                 | 
            
| 95 | 
                +def order_paid_fail(order):  | 
            |
| 96 | 
                + if order.pay_status == OrderInfo.FAIL:  | 
            |
| 97 | 
                + return  | 
            |
| 98 | 
                +  | 
            |
| 99 | 
                + order.pay_status = OrderInfo.FAIL  | 
            |
| 100 | 
                + order.save()  | 
            |
| 101 | 
                +  | 
            |
| 102 | 
                +  | 
            |
| 103 | 
                +@logit  | 
            |
| 104 | 
                +@transaction.atomic  | 
            |
| 105 | 
                +def wx_order_query_api(request):  | 
            |
| 106 | 
                + """  | 
            |
| 107 | 
                + 订单查询  | 
            |
| 108 | 
                + :param request:  | 
            |
| 109 | 
                + :return:  | 
            |
| 110 | 
                + """  | 
            |
| 111 | 
                +    order_id = request.POST.get('order_id', '')
               | 
            |
| 112 | 
                +    transaction_id = request.POST.get('transaction_id', '')
               | 
            |
| 113 | 
                +  | 
            |
| 114 | 
                + try:  | 
            |
| 115 | 
                + order = OrderInfo.objects.get(order_id=order_id)  | 
            |
| 116 | 
                + except OrderInfo.DoesNotExist:  | 
            |
| 117 | 
                + return response(OrderStatusCode.WX_ORDER_NOT_FOUND)  | 
            |
| 118 | 
                +  | 
            |
| 119 | 
                + if order.pay_status == OrderInfo.PAID:  | 
            |
| 120 | 
                +        return JsonResponse({
               | 
            |
| 121 | 
                + 'status': 200,  | 
            |
| 122 | 
                + 'message': 'Order Pay Success',  | 
            |
| 123 | 
                + 'description': u'订单支付成功',  | 
            |
| 124 | 
                +            'data': {
               | 
            |
| 125 | 
                +  | 
            |
| 126 | 
                + }  | 
            |
| 127 | 
                + })  | 
            |
| 128 | 
                + elif order.pay_status == OrderInfo.FAIL:  | 
            |
| 129 | 
                + return response(OrderStatusCode.WX_ORDER_PAY_FAIL)  | 
            |
| 130 | 
                +  | 
            |
| 131 | 
                + # 根据 trade_type 获取 wechat 配置  | 
            |
| 132 | 
                +    wechat = WECHAT.get(order.trade_type, {})
               | 
            |
| 133 | 
                + # WeChatPay 初始化  | 
            |
| 134 | 
                +    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
               | 
            |
| 135 | 
                +  | 
            |
| 136 | 
                + # 订单查询  | 
            |
| 137 | 
                + query_data = wxpay.order.query(transaction_id, order_id)  | 
            |
| 138 | 
                + # 签名校验  | 
            |
| 139 | 
                + if not wxpay.check_signature(query_data):  | 
            |
| 140 | 
                + return response(OrderStatusCode.SIGN_CHECK_FAIL)  | 
            |
| 141 | 
                +  | 
            |
| 142 | 
                + # 交易状态  | 
            |
| 143 | 
                +    trade_state = query_data.get('trade_state')
               | 
            |
| 144 | 
                + # 订单状态判断更新  | 
            |
| 145 | 
                + if trade_state == 'SUCCESS': # 订单支付成功  | 
            |
| 146 | 
                + order_paid_success(order)  | 
            |
| 147 | 
                +        return JsonResponse({
               | 
            |
| 148 | 
                + 'status': 200,  | 
            |
| 149 | 
                + 'message': 'Order Pay Success',  | 
            |
| 150 | 
                + 'description': u'订单支付成功',  | 
            |
| 151 | 
                +            'data': {
               | 
            |
| 152 | 
                +  | 
            |
| 153 | 
                + }  | 
            |
| 154 | 
                + })  | 
            |
| 155 | 
                + elif trade_state == 'NOTPAY': # 订单未支付  | 
            |
| 156 | 
                + return response(OrderStatusCode.WX_ORDER_NOT_PAY)  | 
            |
| 157 | 
                + elif trade_state == 'USERPAYING': # 订单支付中  | 
            |
| 158 | 
                + return response(OrderStatusCode.WX_ORDER_PAYING)  | 
            |
| 159 | 
                + else: # 订单支付失败  | 
            |
| 160 | 
                + order_paid_fail(order)  | 
            |
| 161 | 
                + return response(OrderStatusCode.WX_ORDER_PAY_FAIL)  | 
            |
| 162 | 
                +  | 
            |
| 163 | 
                +  | 
            |
| 87 | 164 | 
                @logit  | 
            
| 88 | 165 | 
                @transaction.atomic  | 
            
| 89 | 166 | 
                def wx_notify_url_api(request):  | 
            
                @@ -98,6 +175,17 @@ def wx_notify_url_api(request):  | 
            ||
| 98 | 175 | 
                # 解析 XML 失败  | 
            
| 99 | 176 | 
                return HttpResponse(settings.WXPAY_NOTIFY_FAIL)  | 
            
| 100 | 177 | 
                 | 
            
| 178 | 
                +    trade_type = data.get('trade_type', '')
               | 
            |
| 179 | 
                +  | 
            |
| 180 | 
                + # 根据 trade_type 获取 wechat 配置  | 
            |
| 181 | 
                +    wechat = WECHAT.get(trade_type, {})
               | 
            |
| 182 | 
                + # WeChatPay 初始化  | 
            |
| 183 | 
                +    wxpay = WeChatPay(wechat.get('appID'), wechat.get('apiKey'), wechat.get('mchID'))
               | 
            |
| 184 | 
                +  | 
            |
| 185 | 
                + # 签名校验  | 
            |
| 186 | 
                + if not wxpay.check_signature(data):  | 
            |
| 187 | 
                + return response(OrderStatusCode.SIGN_CHECK_FAIL)  | 
            |
| 188 | 
                +  | 
            |
| 101 | 189 | 
                     out_trade_no = data.get('out_trade_no', '')
               | 
            
| 102 | 190 | 
                     return_code = data.get('return_code', '')
               | 
            
| 103 | 191 | 
                     result_code = data.get('result_code', '')
               | 
            
                @@ -106,9 +194,9 @@ def wx_notify_url_api(request):  | 
            ||
| 106 | 194 | 
                return HttpResponse(settings.WXPAY_NOTIFY_FAIL)  | 
            
| 107 | 195 | 
                 | 
            
| 108 | 196 | 
                try:  | 
            
| 109 | 
                - order = OrderInfo.objects.get(order=out_trade_no)  | 
            |
| 197 | 
                + order = OrderInfo.objects.get(order_id=out_trade_no)  | 
            |
| 110 | 198 | 
                except OrderInfo.DoesNotExist:  | 
            
| 111 | 
                - return HttpResponse(settings.WXPAY_NOTIFY_FAIL)  | 
            |
| 199 | 
                + return response(OrderStatusCode.WX_ORDER_NOT_FOUND)  | 
            |
| 112 | 200 | 
                 | 
            
| 113 | 201 | 
                order_paid_success(order)  | 
            
| 114 | 202 | 
                 | 
            
                @@ -64,6 +64,11 @@ class GroupPhotoStatusCode(BaseStatusCode):  | 
            ||
| 64 | 64 | 
                class OrderStatusCode(BaseStatusCode):  | 
            
| 65 | 65 | 
                """ 订单/支付相关错误码 4040xx """  | 
            
| 66 | 66 | 
                WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, u'WX Unified Order Fail', description=u'微信统一下单失败')  | 
            
| 67 | 
                + WX_ORDER_NOT_FOUND = StatusCodeField(404001, u'WX Order Not Found', description=u'订单不存在')  | 
            |
| 68 | 
                + WX_ORDER_NOT_PAY = StatusCodeField(404002, u'WX Order Not Pay', description=u'订单未支付')  | 
            |
| 69 | 
                + WX_ORDER_PAYING = StatusCodeField(404003, u'WX Order Paying', description=u'订单支付中')  | 
            |
| 70 | 
                + WX_ORDER_PAY_FAIL = StatusCodeField(404009, u'WX Order Pay Fail', description=u'微信支付失败')  | 
            |
| 71 | 
                + SIGN_CHECK_FAIL = StatusCodeField(404010, u'Sign Check Fail', description=u'签名校验失败')  | 
            |
| 67 | 72 | 
                 | 
            
| 68 | 73 | 
                 | 
            
| 69 | 74 | 
                class MessageStatusCode(BaseStatusCode):  |